﻿using FlyRemote.Base;
using FlyRemote.Remote;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

// 长度与当前的 编译平台有关 

using size_t = System.UIntPtr;

namespace FlyRemote.Scanning.Searcher
{

    /// <summary>
    /// 注意 这不是一个比较器, 因为不是逐个元素进行比较  
    /// 针对 字节数组,  字符串,  以及特征码 设计
    /// </summary>
    public class BytesSearcher
    {


        /// <summary>
        ///  msvcrt.dll 中有这个  memchr 
        /// </summary>

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr memchr(IntPtr ptr, byte chr, size_t size);

        /// <summary>
        /// 如果其实现 已经做到 先8字节比较 , 后单字节比较 , 那么效率应该比 纯代码实现 要快 
        /// 另外一点 , 一旦发现不同,即时返回 
        /// </summary>
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern int memcmp(IntPtr b1, IntPtr b2, int count);




        private SnapshotCell Cell { get; set; }


        private byte[] array;



        private DataType dataType;

        //public BytesSearcher(SnapshotCell region, ConstraintNode constraints)
        //{

        //    this.Cell = region;

        //    if (constraints is ScanConstraint sc)
        //    {
        //        if (constraints.ElementType.Code == Base.DataType.TypeCode.ByteArray)
        //        {
        //            this.array = (byte[])sc.ConstraintValue;
        //        }
        //        else if (constraints.ElementType.Code == Base.DataType.TypeCode.Ansi)
        //        {
        //            this.array = Encoding.ASCII.GetBytes(sc.ConstraintValue as string);
        //        }
        //        else if (constraints.ElementType.Code == Base.DataType.TypeCode.Utf8)
        //        {
        //            this.array = Encoding.UTF8.GetBytes(sc.ConstraintValue as string);
        //        }
        //        else if (constraints.ElementType.Code == Base.DataType.TypeCode.Utf16)
        //        {
        //            this.array = Encoding.Unicode.GetBytes(sc.ConstraintValue as string);

        //        }

        //        // 此处已可以 确定 类型的真实长度 
        //        this.dataType = new DataType(sc.ElementType.Code, (short)array.Length);

        //    }
        //    else
        //    {
        //        throw new ArgumentException();
        //    }

        //}


        public BytesSearcher(SnapshotCell region, byte[] arr, DataType dataType)
        {

            this.Cell = region;

            this.array = arr;
            this.dataType = dataType;


        }



        public IList<SnapshotCell> Compare()
        {

            List<SnapshotCell> list = new List<SnapshotCell>(0x10);

            long ptr = (long)Marshal.UnsafeAddrOfPinnedArrayElement(Cell.ReadGroup.CurrentValues, 0);

            // 这里首次查找, 此时 Cell 大小等于 读取组 
            if (Cell.RegionSize == this.Cell.ReadGroup.RegionSize)
            {
                return Search(Cell.ReadGroup, array);

            }

            // 这里是比较 
            else
            {

                IntPtr arrData = Marshal.UnsafeAddrOfPinnedArrayElement(this.array, 0);

                if (memcmp((IntPtr)((long)ptr + Cell.ReadGroupOffset), arrData, this.array.Length) == 0)
                {
                    var c = new SnapshotCell(this.Cell.ReadGroup, Cell.ReadGroupOffset, this.array.Length);
                    list.Add(c);
                }



            }

            return list;

        }



        public static IList<SnapshotCell> Search(ReadGroup group, byte[] arr)
        {
            List<SnapshotCell> list = new List<SnapshotCell>(0x10);

            long ptr = (long)Marshal.UnsafeAddrOfPinnedArrayElement(group.CurrentValues, 0);


            IntPtr arrData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0);

            long ptrEnd = ((long)ptr + group.RegionSize);

            long cur = ptr;


            while (cur < ptrEnd)
            {
                cur = (long)memchr((IntPtr)cur, arr[0], (size_t)(ptrEnd - cur));

                if (cur == 0)
                    break;

                if (memcmp((IntPtr)cur, arrData, arr.Length) == 0)
                {
                    var c = new SnapshotCell(group, (int)(cur - ptr), arr.Length);
                    list.Add(c);
                }

                cur++;
            }


            return list;

        }




        public static IList<SnapshotCell> Search(ReadGroup group, byte firstByte, Func<IntPtr, int> func)
        {
            List<SnapshotCell> list = new List<SnapshotCell>(0x10);

            long ptr = (long)Marshal.UnsafeAddrOfPinnedArrayElement(group.CurrentValues, 0);

            long ptrEnd = ((long)ptr + group.RegionSize);

            long cur = ptr;


            while (cur < ptrEnd)
            {
                cur = (long)memchr((IntPtr)cur, firstByte, (size_t)(ptrEnd - cur));

                if (cur == 0)
                    break;

                int ok = func((IntPtr)cur);
                if (ok > 0)
                {
                    var c = new SnapshotCell(group, (int)(cur - ptr), ok);
                    list.Add(c);
                }

                cur++;
            }


            return list;

        }

    }
}
